package com.engine.salary.util;

import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.TypeReference;
import com.engine.salary.encrypt.AESEncryptUtil;
import com.engine.salary.entity.salaryBill.param.SalaryBillGetTokenParam;
import com.engine.salary.exception.SalaryRunTimeException;
import com.engine.salary.util.db.IdGenerator;
import org.apache.commons.lang3.StringUtils;
import weaver.conn.RecordSet;
import weaver.general.BaseBean;
import weaver.rsa.security.RSA;

import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.net.HttpURLConnection;
import java.net.URL;
import java.security.KeyManagementException;
import java.security.NoSuchAlgorithmException;
import java.time.LocalDateTime;
import java.util.HashMap;
import java.util.Map;

public class SalaryTokenUtil {

    /**
     * 通过注册返回的OA系统公钥和秘钥获取token
     *
     * @param address OA地址
     * @return
     * @throws NoSuchAlgorithmException
     * @throws KeyManagementException
     */
//    public static Map<String, Object> testGetoken(String address) throws NoSuchAlgorithmException, KeyManagementException {
//        Map<String, String> heads = new HashMap<>();
//        Map<String, Object> datas = testRegist(address); // 注册接口返回的secrit私钥和spk公钥可以在第一次调用后，第三方系统保存起来，之后调用可以不用再调用这个注册接口
//        //ECOLOGY返回的系统公钥
//        String spk = (String) (datas.get("spk"));
//        RSA rsa = new RSA();
//        //对秘钥进行加密传输，防止篡改数据
//        String secret = rsa.encrypt(null, (String) (datas.get("secrit")), null, "utf-8", spk, false);
//        //封装参数到请求头
//        heads.put("appid", APPID);
//        heads.put("secret", secret);
//        //调用ECOLOGY系统接口进行注册
//        String data = post(address + "/api/ec/dev/auth/applytoken", null, heads);
//        System.out.println("=====testGetoken=====" + data);
//        return JSONObject.parseObject(data, new TypeReference<Map<String, Object>>() {
//        });
//    }

    /**
     * 注册第三方系统到OA系统，第一次用APPID获取到公钥spk和私钥secret，第三方系统可以保存，下次不用在请求注册接口
     *
     * @param address OA地址
     * @return
     * @throws NoSuchAlgorithmException
     * @throws KeyManagementException
     */
//    public static Map<String, Object> testRegist(String address) throws NoSuchAlgorithmException, KeyManagementException {
//        Map<String, String> heads = new HashMap<>();
//        //获取当前异构系统RSA加密的公钥
//        String cpk = new RSA().getRSA_PUB();
//        //封装参数到请求头
//        heads.put("appid", APPID);
//        heads.put("cpk", cpk);
//        //调用ECOLOGY系统接口进行注册
//        String data = post(address + "/api/ec/dev/auth/regist", null, heads);
//        System.out.println("=====testRegist=====" + data);
//        return JSONObject.parseObject(data, new TypeReference<Map<String, Object>>() {
//        });
//    }

    /**
     * 第一次获取Token，需要先注册
     *
     * @return
     */
    public static Map<String, String> GetToken(SalaryBillGetTokenParam param)  {
        String uid = "";
        if (StringUtils.isNotBlank(param.getSalaryCode())) {
            uid = AESEncryptUtil.decrypt4SalaryBill(param.getSalaryCode());
        } else {
            uid = param.getRecipient();
        }
        Map<String, String> heads = new HashMap<>();
        if (StringUtils.isBlank(uid)) {
            return heads;
        }
        BaseBean baseBean = new BaseBean();
        // 获取是否是https
        String isHttps = baseBean.getPropValue("hrmSalaryBillToken", "is_https");
        String httpKey = (StringUtils.isNotBlank(isHttps) && isHttps.equals("true")) ? "https://" : "http://";
        RecordSet rs = new RecordSet();
        Map<String, String> resultMap = new HashMap<>();

        // 获取appid的id
        String appidId = baseBean.getPropValue("hrmSalaryBillToken", "appid_id");
        if (StringUtils.isBlank(appidId)) {
            return resultMap;
        }
        String ip = baseBean.getPropValue("hrmSalaryBillToken", "ip");
        rs.execute("select APPID from ECOLOGY_BIZ_EC where id =" + appidId);
        // 获取appid
        String appid ="";
        if (rs.next() && StringUtils.isNotEmpty(rs.getString("APPID"))) {
            appid = rs.getString("APPID");
        } else {
            return resultMap;
        }
        String sql= " SELECT conf_value  FROM hrsa_salary_sys_conf t WHERE delete_type = 0   AND conf_key = 'SALARY_TOKEN_SECRET'";
        rs.execute(sql);
        String secret = "";
        if (rs.next() && StringUtils.isNotBlank(rs.getString("conf_value"))) {
            // 从数据库中拿secret
            secret = rs.getString("conf_value");
        } else {
            sql= " update hrsa_salary_sys_conf set delete_type=1 WHERE delete_type = 0   AND conf_key in( 'SALARY_TOKEN_SECRET', 'SALARY_TOKEN_SPK')";
            rs.execute(sql);
            // 注册获取secret
            // 获取当前异构系统RSA加密的公钥
            String cpk = new RSA().getRSA_PUB();
            //封装参数到请求头
            heads.put("appid", appid);
            heads.put("cpk", cpk);
            // 调用ECOLOGY系统接口进行注册
            String data = post(httpKey + ip + "/api/ec/dev/auth/regist", null, heads);
            Map<String, Object> datas = JSONObject.parseObject(data, new TypeReference<Map<String, Object>>() {});
            // ECOLOGY返回的系统公钥
            String spk = (String) (datas.get("spk"));
            RSA rsa = new RSA();
            // 对秘钥进行加密传输，防止篡改数据
            secret = rsa.encrypt(null, (String) (datas.get("secrit")), null, "utf-8", spk, false);
            // secret存库
            String date = SalaryDateUtil.getFormatLocalDateTime(LocalDateTime.now());
            sql = String.format("insert into hrsa_salary_sys_conf(id, conf_key, conf_value, title, module, order_weight, delete_type, create_time, update_time) values (%s,'%s','%s','%s','%s',%s,%s,'%s','%s')",
                    IdGenerator.generate(), "SALARY_TOKEN_SECRET", secret, "token", "basic",0,0,date,date);
            rs.execute(sql);
            // 保存spk
            sql = String.format("insert into hrsa_salary_sys_conf(id, conf_key, conf_value, title, module, order_weight, delete_type, create_time, update_time) values (%s,'%s','%s','%s','%s',%s,%s,'%s','%s')",
                    IdGenerator.generate(), "SALARY_TOKEN_SPK", spk, "spk", "basic",0,0,date,date);
            rs.execute(sql);
        }
        //封装参数到请求头
        heads.put("appid", appid);
        heads.put("secret", secret);
        //调用ECOLOGY系统接口进行注册
        String data2 = post(httpKey + ip + "/api/ec/dev/auth/applytoken", null, heads);
        // 通过第一步注册许可时返回spk公钥对userid进行加密生成的密文
        sql= " SELECT conf_value  FROM hrsa_salary_sys_conf t WHERE delete_type = 0   AND conf_key = 'SALARY_TOKEN_SPK'";
        rs.execute(sql);
        if (rs.next()){
            String spk = rs.getString("conf_value");
            // 对uid进行加密
            RSA rsa = new RSA();
            String encryptUid = rsa.encrypt(null, uid.toString(), null, "utf-8", spk, false);
            String token = (String)JSONObject.parseObject(data2, new TypeReference<Map<String, Object>>() {}).get("token");
            resultMap.put("userid", encryptUid);
            resultMap.put("token", token);
            resultMap.put("appid",appid);
            return resultMap;
        } else {
            throw new SalaryRunTimeException("spk不存在");
        }
    }


    /**
     * 此方法仅供参考，第三方系统可采用自己的方式调用http接口
     *
     * @param path 请求路径
     * @param data 请求参数
     * @return
     */
    public static String post(String path, Map<String, String> params, Map<String, String> data) {
        try {
            String str = "";
//            if (params != null) {
//                StringBuilder stringBuilder = new StringBuilder("?");
//                for (Map.Entry<String, String> entry : params.entrySet()) {
//                    stringBuilder.append(entry.getKey()).append("=").append(entry.getValue()).append("&");
//                }
//                if (stringBuilder.length() > 1)
//                    path += stringBuilder.substring(0, stringBuilder.length() - 1);
//            }
            URL url = new URL(path);
            //打开和url之间的连接
            HttpURLConnection conn = (HttpURLConnection) url.openConnection();
//            PrintWriter out = null;
            // 请求参数 编码为 utf-8
            //请求方式
            conn.setRequestMethod("POST");
            //设置通用的请求属性
            conn.setRequestProperty("accept", "*/*");
            conn.setRequestProperty("connection", "Keep-Alive");
            conn.setRequestProperty("user-agent", "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1)");
            if (data != null) {
                for (Map.Entry<String, String> entry : data.entrySet()) {
                    conn.setRequestProperty(entry.getKey(), entry.getValue());
                }
            }
            //设置是否向httpUrlConnection输出，设置是否从httpUrlConnection读入，此外发送post请求必须设置这两个
            //最常用的Http请求无非是get和post，get请求可以获取静态页面，也可以把参数放在URL字串后面，传递给servlet，
            //post与get的 不同之处在于post的参数不是放在URL字串里面，而是放在http请求的正文内。
            conn.setDoOutput(true);
            conn.setDoInput(true);
            OutputStreamWriter out = new OutputStreamWriter(conn.getOutputStream(), "utf-8");
            if (params != null) {
                out.write(mapToStr(params));
            }
            //缓冲数据
            out.flush();
            out.close();
            //获取URLConnection对象对应的输入流
            InputStream is = conn.getInputStream();
            //构造一个字符流缓存
            BufferedReader br = new BufferedReader(new InputStreamReader(is, "utf-8"));
            String result = "";
            while ((str = br.readLine()) != null) {
                result = str;
            }
            //关闭流
            is.close();
            //断开连接，最好写上，disconnect是在底层tcp socket链接空闲时才切断。如果正在被其他线程使用就不切断。
            //固定多线程的话，如果不disconnect，链接会增多，直到收发不出信息。写上disconnect后正常一些。
            conn.disconnect();
            return result;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 将Map转换成字符串参数，用于POST GET 请求
     *
     * @param map
     * @return
     */
    public static String mapToStr(Map<String, String> map) {
        StringBuilder stringBuilder = new StringBuilder();
        if (map != null) {
            for (Map.Entry<String, String> entry : map.entrySet()) {
                stringBuilder.append(entry.getKey());
                if (entry.getValue() != null) {
                    stringBuilder.append("=").append(entry.getValue());
                }
                stringBuilder.append("&");
            }
        }
        if (stringBuilder.length() > 0) {
            return stringBuilder.substring(0, stringBuilder.length() - 1);
        }
        return null;
    }
}
